package com.googlecode.gendevcode.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.googlecode.gendevcode.common.Cache;
import com.googlecode.gendevcode.model.pdm.ColumnPdmXml;
import com.googlecode.gendevcode.model.pdm.DataTypePdmXml;
import com.googlecode.gendevcode.model.pdm.TablePdmXml;
import com.googlecode.gendevcode.model.pdm.ViewPdmXml;
import com.googlecode.gendevcode.service.PdmService;
import com.googlecode.gendevcode.service.basic.ServiceSupport;

/**
 * 读取PDM文件实现类
 * @author devilishking
 *
 */
public class PdmServiceImpl extends ServiceSupport<PdmServiceImpl> 
							implements PdmService {
		
	/**
	 * 获取表和视图的关联关系
	 * @param viewList	             视图列表<视图信息>
	 * @param viewMap	             视图集合<视图编号, 视图信息>
	 * @param tableIdListMap 表和视图的关联关系集合<视图编号, List<表编号>>
	 * @param doc            文档视图
	 * @throws Exception
	 */
	public void setViewTabelId(List<ViewPdmXml> viewList, 
							   Map<String, ViewPdmXml> viewMap,
							   Map<String, List<String>> tableIdListMap, 
							   Document doc) throws Exception{
		NodeList physicalDiagramsNodeList = doc.getElementsByTagName("c:PhysicalDiagrams");
		for(int i = 0; i < physicalDiagramsNodeList.getLength(); i++){
			NodeList physicalDiagramNodeList = physicalDiagramsNodeList.item(i).getChildNodes();
			for(int j = 0; j < physicalDiagramNodeList.getLength(); j++){
				Node physicalDiagramNode = physicalDiagramNodeList.item(j);	
				if ("o:PhysicalDiagram".equals(physicalDiagramNode.getNodeName())){
					NodeList fieldNodeList = physicalDiagramNode.getChildNodes();
					ViewPdmXml viewPdmXml = new ViewPdmXml();
					viewPdmXml.setId(physicalDiagramNode.getAttributes().getNamedItem("Id").getNodeValue());
					for(int k = 0; k < fieldNodeList.getLength(); k++){
						Node fieldNode = fieldNodeList.item(k);	
						String nodeName = fieldNode.getNodeName();
						if ("a:Name".equals(nodeName)){
							viewPdmXml.setName(fieldNode.getTextContent());
						}
						else if ("a:Comment".equals(nodeName)){
							viewPdmXml.setPackageCode(fieldNode.getTextContent());
						}
						else if ("c:Symbols".equals(nodeName)){
							NodeList symbolsNodeList = fieldNode.getChildNodes();
							for(int m = 0; m < symbolsNodeList.getLength(); m++){
								Node symbolsNode = symbolsNodeList.item(m);
								if ("o:TableSymbol".equals(symbolsNode.getNodeName())){
									NodeList tableSymbolList = symbolsNode.getChildNodes();
									for (int n = 0; n < tableSymbolList.getLength(); n++) {
										Node tableSymbolNode = tableSymbolList.item(n);
										if ("c:Object".equals(tableSymbolNode.getNodeName())){
											NodeList objectlNodeList= tableSymbolNode.getChildNodes();
											for (int l = 0; l < objectlNodeList.getLength(); l++) {
												Node objectNode = objectlNodeList.item(l);
												if ("o:Table".equals(objectNode.getNodeName())){
													List<String> tableIdList = tableIdListMap.get(viewPdmXml.getId());
													if (tableIdList == null){
														tableIdList = new ArrayList<String>();
													}
													tableIdList.add(objectNode.getAttributes().getNamedItem("Ref").getNodeValue());
													tableIdListMap.put(viewPdmXml.getId(), tableIdList);
												}
											}
										}
									}
								}
							}
						}
					}
					//仅处理存在表定义的物理视图
					if(tableIdListMap.containsKey(viewPdmXml.getId())){
						viewList.add(viewPdmXml);
						viewMap.put(viewPdmXml.getId(), viewPdmXml);
					}
				}
			}
		}
	}
	
	/**
	 * 获取表信息
	 * @param tablePdmXmlMap 	        表信息集合<表编号, 表信息>
	 * @param tablePdmXmlByNameMap 表信息集合<表名, 表信息>
	 * @param viewList	                             视图列表<视图信息>
	 * @param tableIdListMap 	        表和视图的关联关系集合<视图编号, List<表编号>>
	 * @param doc 			  	        文档视图
	 * @throws Exception
	 */
	public void setTableInfo(Map<String, TablePdmXml> tablePdmXmlMap, 
							 Map<String, TablePdmXml> tablePdmXmlByNameMap,
							 List<ViewPdmXml> viewList,
							 Map<String, List<String>> tableIdListMap,
							 Document doc) throws Exception{
		NodeList tablesNodeList = doc.getElementsByTagName("c:Tables");
		for(int i = 0; i < tablesNodeList.getLength(); i++){
			NodeList tableNodeList = tablesNodeList.item(i).getChildNodes();
			for(int j = 0; j < tableNodeList.getLength(); j++){
				Node tableNode = tableNodeList.item(j);
				if ("o:Table".equals(tableNode.getNodeName())){
					TablePdmXml tablePdmXml = new TablePdmXml();
					String pkId = "";
					tablePdmXml.setId(tableNode.getAttributes().getNamedItem("Id").getNodeValue());
					NodeList fieldNodeList = tableNode.getChildNodes();
					for(int k = 0; k < fieldNodeList.getLength(); k++){
						Node fieldNode = fieldNodeList.item(k);
						if ("a:Name".equals(fieldNode.getNodeName())){
							tablePdmXml.setName(fieldNode.getTextContent());
						}
						else if ("a:Code".equals(fieldNode.getNodeName())){
							tablePdmXml.setCode(fieldNode.getTextContent());
						}
						else if ("a:Comment".equals(fieldNode.getNodeName())){
							tablePdmXml.setClassName(fieldNode.getTextContent());
						}
						else if ("c:Columns".equals(fieldNode.getNodeName())){
							tablePdmXml.setColumnPdmXmlList(setColumnsInfo(fieldNode));
						}
						else if ("c:Keys".equals(fieldNode.getNodeName())){
							pkId = findPkIdByKeyNode(fieldNode.getChildNodes());
						}
					}
					if (pkId != null && pkId.trim().length() > 0){
						List<ColumnPdmXml> columnPdmXmlList = tablePdmXml.getColumnPdmXmlList();
						if (columnPdmXmlList != null && !columnPdmXmlList.isEmpty()){
							for(ColumnPdmXml columnPdmXml : columnPdmXmlList){
								if (pkId.equals(columnPdmXml.getId())){
									columnPdmXml.setIsPK(true);
								}
							}
						}
						tablePdmXml.setColumnPdmXmlList(columnPdmXmlList);
					}
					tablePdmXml = formaTableObject(tablePdmXml);
					tablePdmXmlMap.put(tablePdmXml.getId(), tablePdmXml);
					tablePdmXmlByNameMap.put(tablePdmXml.getCode(), tablePdmXml);
				}
			}
		}
		for(ViewPdmXml viewPdmXml : viewList){
			//视图中存在表
			if(tableIdListMap.containsKey(viewPdmXml.getId())){
				List<String> tableIdList = tableIdListMap.get(viewPdmXml.getId());			
				for(String tableId : tableIdList){
					TablePdmXml tablePdmXml = tablePdmXmlMap.get(tableId);
					tablePdmXml.setViewId(viewPdmXml.getId());
					tablePdmXmlMap.put(tablePdmXml.getId(), tablePdmXml);
				}
			}			
		}
	}
	
	/**
	 * 获取字段信息
	 * @param fieldNode  文档字段节点
	 * @return
	 * @throws Exception
	 */
	private List<ColumnPdmXml> setColumnsInfo(Node fieldNode) throws Exception {
		List<ColumnPdmXml> columnPdmXmlList = new ArrayList<ColumnPdmXml>();
		NodeList columnsNodeList = fieldNode.getChildNodes();
		for(int i = 0; i < columnsNodeList.getLength(); i++){
			Node columnsNode = columnsNodeList.item(i);
			if ("o:Column".equals(columnsNode.getNodeName())){
				ColumnPdmXml columnPdmXml = new ColumnPdmXml();
				columnPdmXml.setId(columnsNode.getAttributes().getNamedItem("Id").getNodeValue());
				NodeList columNodeList = columnsNode.getChildNodes();
				for(int j = 0; j < columNodeList.getLength(); j++){
					Node columNode = columNodeList.item(j);
					if ("a:Name".equals(columNode.getNodeName())){
						columnPdmXml.setName(columNode.getTextContent());
					}
					else if ("a:Code".equals(columNode.getNodeName())){
						columnPdmXml.setCode(columNode.getTextContent());
					}
					else if ("a:DataType".equals(columNode.getNodeName())){
						columnPdmXml.setDataType(columNode.getTextContent().toUpperCase());
					}
					else if ("a:Length".equals(columNode.getNodeName())){
						columnPdmXml.setLength(columNode.getTextContent());
					}
					else if ("a:Comment".equals(columNode.getNodeName())){
						columnPdmXml.setDictionary(columNode.getTextContent());
					}
					else if ("a:Mandatory".equals(columNode.getNodeName())){
						columnPdmXml.setMandatory(true);
					}
				}
				columnPdmXmlList.add(columnPdmXml);
			}
		}
		return columnPdmXmlList;
	}

	/**
	 * 根据主键节点获取主键字段的编号
	 * @param keyNodeList 主键节点列表
	 * @return
	 * @throws Exception
	 */
	private static String findPkIdByKeyNode(NodeList keyNodeList) throws Exception {
		String pkId = null;
		for(int i = 0; i < keyNodeList.getLength(); i++){
			Node keyNode = keyNodeList.item(i);
			if ("o:Key".equals(keyNode.getNodeName())){
				NodeList keyColumnNodeList = keyNode.getChildNodes();
				for(int j = 0; j < keyColumnNodeList.getLength(); j++){
					Node keyColumnNode = keyColumnNodeList.item(j);
					if ("c:Key.Columns".equals(keyColumnNode.getNodeName())){
						NodeList columnNode = keyColumnNode.getChildNodes();
						for(int m = 0; m < columnNode.getLength(); m++){
							Node objNode = columnNode.item(m);
							if ("o:Column".equals(objNode.getNodeName())){
								pkId = objNode.getAttributes().getNamedItem("Ref").getNodeValue();
							}
						}
					}
				}
			}
		}
		return pkId;
	}	
	
	/**
	 * 格式化表结构信息
	 * @param tablePdmXml 表结构信息
	 * @return
	 * @throws Exception
	 */
	private TablePdmXml formaTableObject(TablePdmXml tablePdmXml) throws Exception{
		List<DataTypePdmXml> dataTypePdmXmlList = Cache.getInstance().getDataTypePdmXmlList();
		List<ColumnPdmXml> columnPdmXmlList = tablePdmXml.getColumnPdmXmlList();
		List<String> importClassList = new ArrayList<String>();
		Map<String, String> importClassMap = new HashMap<String, String>();
		for(ColumnPdmXml columnPdmXml : columnPdmXmlList){
			for(DataTypePdmXml dataTypePdmXml : dataTypePdmXmlList){
				String dataType = dataTypePdmXml.getDataType();
				boolean isPass = false;
				if (dataTypePdmXml.getIsMatch()){
					//modified by chenjb 2012-07-13
					if(columnPdmXml.getDataType()!=null){
						isPass = Pattern.compile(dataType).matcher(columnPdmXml.getDataType()).find();
					}else{
						setWarn("【" + tablePdmXml.getName() + "." + columnPdmXml.getCode() + "】dataType is null!") ;
					}
				}
				else{
					isPass = dataType.equals(columnPdmXml.getDataType());
				}
				if (isPass){
					columnPdmXml.setDataType(dataTypePdmXml.getExchangeType());
					if (dataTypePdmXml.getRemark() != null && dataTypePdmXml.getRemark().trim().length() > 0){
						columnPdmXml.setRemark(dataTypePdmXml.getRemark());
					}
					if (dataTypePdmXml.getImportClass() != null 
							&& dataTypePdmXml.getImportClass().trim().length() > 0
							&& importClassMap.get(dataTypePdmXml.getImportClass()) == null){
						importClassList.add(dataTypePdmXml.getImportClass());
						importClassMap.put(dataTypePdmXml.getImportClass(), dataTypePdmXml.getImportClass());
					}
					break;
				}
			}
			
			if (columnPdmXml.getDictionary() != null && columnPdmXml.getDictionary().trim().length() > 0){
				String dictionary = columnPdmXml.getDictionary().trim();
				columnPdmXml.setDictionary("[" + dictionary.substring(0, dictionary.length() - 1) + "]");
			}
			//modified by chenjb 2012-07-13
			int dateTypeLen = columnPdmXml.getDataType()!=null ? columnPdmXml.getDataType().length() : 0 ;
			int codeLen     = columnPdmXml.getCode()!=null ? columnPdmXml.getCode().length() : 0 ;
			int spaceNum = 35 - dateTypeLen - codeLen;
			StringBuffer space = new StringBuffer();
			for(int i = 0; i < spaceNum; i++){
				space.append(" ");
			}
			columnPdmXml.setSpace(space.toString());
			columnPdmXml.replaceRemark();
		}
		if (!importClassList.isEmpty()){
			tablePdmXml.setImportClassList(importClassList);
		}		
		return tablePdmXml;
	}
}